home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-05 / drivers1.zip / ETHERSL.ASM < prev    next >
Assembly Source File  |  1992-01-23  |  31KB  |  1,295 lines

  1. version    equ    5
  2.  
  3.     include    defs.asm
  4.  
  5. ;Ported from Phil Karn's asy.c and slip.c, a C-language driver for the IBM-PC
  6. ;8250 by Russell Nelson.  Any bugs are due to Russell Nelson.
  7. ;16550 support ruthlessly stolen from Phil Karn's 8250.c. Bugs by Denis DeLaRoca
  8. ;
  9. ; Modified by Michael Martineau to provide a class 1 interface.
  10. ; Additional modifications by Joe Doupnik, jrd@cc.usu.edu, 5 Nov 1991
  11. ;  Do not use "c0h" as leading vendor byte in artifical Ethernet address.
  12. ;  Use originator's Ethernet address as destination of ARP Reply address.
  13.  
  14. ;  Copyright, 1988, 1989, Russell Nelson
  15.  
  16. ;   This program is free software; you can redistribute it and/or modify
  17. ;   it under the terms of the GNU General Public License as published by
  18. ;   the Free Software Foundation, version 1.
  19. ;
  20. ;   This program is distributed in the hope that it will be useful,
  21. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23. ;   GNU General Public License for more details.
  24. ;
  25. ;   You should have received a copy of the GNU General Public License
  26. ;   along with this program; if not, write to the Free Software
  27. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  28.  
  29. code    segment    word public
  30.     assume    cs:code, ds:code
  31.  
  32.     include    8250defs.asm
  33.  
  34. ;Slip Definitions
  35. FR_END        equ    0c0h    ;Frame End
  36. FR_ESC        equ    0dbh    ;Frame Escape
  37. T_FR_END    equ    0dch    ;Transposed frame end
  38. T_FR_ESC    equ    0ddh    ;Transposed frame escape
  39.  
  40.     public    int_no
  41. int_no        db    4,0,0,0    ;interrupt number.
  42. io_addr        dw    03f8h,0    ;I/O address for COM1.
  43. baud_rate    dw    12c0h,0    ;We support baud rates higher than 65535.
  44. baudclk        label    word
  45.         dd    115200    ;1.8432 Mhz / 16
  46. hardware_switch    db    0    ;if zero, don't use hardware handshaking.
  47. is_16550        db      0       ;0=no, 1=yes (try using fifo)
  48.  
  49.     public    driver_class, driver_type, driver_name
  50.     public    driver_function, parameter_list
  51.  
  52. driver_class    db    1,0,0,0        ;from the packet spec
  53. driver_type    db    0,0,0,0        ;from the packet spec
  54. driver_name    db    'ETHERSLIP',0    ;name of the driver.
  55. driver_function    db    2
  56. parameter_list    label    byte
  57.     db    1        ;major rev of packet driver
  58.     db    9        ;minor rev of packet driver
  59.     db    14        ;length of parameter list
  60.     db    EADDR_LEN    ;length of MAC-layer address
  61.     dw    GIANT        ;MTU, including MAC headers
  62.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  63.     dw    0        ;(# of back-to-back MTU rcvs) - 1
  64.     dw    0        ;(# of successive xmits) - 1
  65. int_num    dw    0        ;Interrupt # to hook for post-EOI
  66.                 ;processing, 0 == none,
  67.  
  68.   ifdef debug
  69.     public recv_buf_size, recv_buf,    recv_buf_end, recv_buf_head
  70.     public recv_buf_tail, recv_pkt_ready
  71.   endif
  72.  
  73. recv_buf_size    dw    3000,0    ;receive buffer size
  74. recv_buf    dw    ?    ;->receive buffer
  75. recv_buf_end    dw    ?    ;->after end of buffer
  76. recv_buf_head    dw    ?    ;->next character to get
  77. recv_buf_tail    dw    ?    ;->next character to store
  78. recv_pkt_ready    dw    0    ; flag indicating a packet is ready
  79.  
  80.   ifdef debug
  81.     public send_buf
  82.   endif
  83.  
  84. send_buf_size    dw    3000,0    ;send buffer size
  85. send_buf    dw    ?    ;->send buffer
  86. send_buf_end    dw    ?    ;->after end of buffer
  87. send_buf_head    dw    ?    ;->next character to get
  88. send_buf_tail    dw    ?    ;->next character to store
  89.  
  90.   ifdef debug
  91.     public packet_sem, pkt_send_sem, xmit_time
  92.   endif
  93.  
  94. packet_sem    dw    0    ; semaphore for    packets received
  95. pkt_send_sem    dw    0    ; semaphore for    packets xmitted
  96. asyrxint_cnt    dw    0    ; loop counter in asyrxint
  97. xmit_time    dw    0    ; loop timer for asyrxint
  98.  
  99. ;
  100. ; ARP request/reply packet structure.
  101. ;
  102. arp        struc 
  103. arp_hw        dw ?         ; Hardware address length, bytes 
  104. arp_prot    dw ?         ; Protocol type 
  105. arp_hwalen    db ?         ; hardware address length, bytes 
  106. arp_pralen     db ?         ; Length of protocol address 
  107. arp_opcode      dw ?         ; ARP opcode (request/reply) 
  108. arp_shwaddr    db 6 dup(?)    ; Sender hardware address field 
  109. arp_sprotaddr    dd ?        ; Sender Protocol address field 
  110. arp_thwaddr    db 6 dup(?)    ; Target hardware address field 
  111. arp_tprotaddr    dd ?        ; Target protocol address field 
  112. arp        ends
  113.  
  114. ;
  115. ; recv_find() requires a pointer to the Ethernet packet type.  Since
  116. ; the incoming packet does not contain an Ethernet packet type field,
  117. ; memory must be allocated to hold the Ethernet packet type.  Space is
  118. ; required for both IP and ARP types.
  119. ;
  120. ip_type        label    byte
  121.         db    08
  122.         db    00    
  123.  
  124. arp_type    label    byte
  125.         db    08
  126.         db    06    
  127.  
  128. ;
  129. ; Psuedo-Ethernet address to return when get_address() is called.
  130. ;
  131. my_addr        label     byte
  132.         db    0
  133.         db    0
  134.         db    0
  135.         db    12h
  136.         db    34h
  137.         db    56h    
  138. ;
  139. ; Psuedo-Ethernet address to return in the ARP reply packet.
  140. ;
  141. your_addr    label     byte
  142.         db    00
  143.         db    00
  144.         db    0
  145.         db    22h
  146.         db    34h
  147.         db    66h    
  148.  
  149.     public    rcv_modes
  150. rcv_modes    dw    4        ;number    of receive modes in our table.
  151.         dw    0,0,0,rcv_mode_3
  152.  
  153.  
  154.     public    as_send_pkt
  155. ; The Asynchronous Transmit Packet routine.
  156. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  157. ;   interrupts possibly enabled.
  158. ; Exit with nc if ok, or else cy if error, dh set to error number.
  159. ;   es:di and interrupt enable flag preserved on exit.
  160. as_send_pkt:
  161.     ret
  162.  
  163.     public    drop_pkt
  164. ; Drop a packet from the queue.
  165. ; Enter with es:di -> iocb.
  166. drop_pkt:
  167.     assume    ds:nothing
  168.     ret
  169.  
  170.     public    xmit
  171. ; Process a transmit interrupt with the least possible latency to achieve
  172. ;   back-to-back packet transmissions.
  173. ; May only use ax and dx.
  174. xmit:
  175.     assume    ds:nothing
  176.     ret
  177.  
  178.     public    send_pkt
  179. ;
  180. ; mod 7/25/89 John Grover
  181. ; - operates with interrupts on. Xmits one byte per interrupt
  182. ; - only turns transmitter buffer empty interrupt off when
  183. ; - all bytes of all packets are transmitted.
  184.  
  185. send_pkt:
  186. ;enter with es:di->upcall routine, (0:0) if no upcall is desired.
  187. ;  (only if the high-performance bit is set in driver_function)
  188. ;enter with ds:si -> packet, cx = packet length.
  189. ;exit with nc if ok, or else cy if error, dh set to error number.
  190. ;called from telnet layer via software interrupt
  191.  
  192.     assume    ds:nothing
  193. ;    
  194. ; Strip off Ethernet header.
  195. ;
  196.     add    si,12
  197.     mov    ax, word ptr ds:[si]
  198.     add    si,2
  199.     sub    cx,14
  200. ;
  201. ; Check packet type.  If an ARP packet then construct an ARP reply
  202. ; packet. Otherwise, process the incoming IP packet.
  203. ;
  204.     cmp    ax,0608h
  205.     jne    noarp
  206.     call    arp_reply
  207.     jmp    send_pkt_end
  208.  
  209. noarp:
  210.     push    cs
  211.     pop    es
  212.     mov    di,send_buf_tail
  213.     sti                ; enable interrupts
  214.  
  215.     mov    al,FR_END        ;Flush out any line garbage
  216.     call    send_char
  217. ;
  218. ;Copy input to output, escaping special characters
  219. ;
  220. send_pkt_1:
  221.     lodsb
  222.     cmp    al,FR_ESC        ;escape FR_ESC with FR_ESC and T_FR_ESC
  223.     jne    send_pkt_2
  224.     mov    al,FR_ESC
  225.     call    send_char
  226.     mov    al,T_FR_ESC
  227.     jmp    short send_pkt_3
  228. send_pkt_2:
  229.     cmp    al,FR_END        ;escape FR_END with FR_ESC and T_FR_END
  230.     jne    send_pkt_3
  231.     mov    al,FR_ESC
  232.     call    send_char
  233.     mov    al,T_FR_END
  234. send_pkt_3:
  235.     call    send_char
  236.     loop    send_pkt_1
  237.     mov    al,FR_END        ;terminate it with a FR_END
  238.     call    send_char
  239.     mov    send_buf_tail,di
  240.  
  241.     inc    pkt_send_sem        ; increment the semaphore
  242.     cmp    pkt_send_sem, 1        ; see if we need to enable
  243.                     ; xmit buffer empty interrupt
  244.     ja    send_pkt_end
  245.  
  246.     mov    ah,IER_TxE        ; enable xmit buffer empty interrupt
  247.     cmp    hardware_switch,0    ; should we do hardware handshaking?
  248.     je    send_pkt_4        ; no, just enable TxE.
  249. ;
  250. ; Enable modem status and (maybe) transmitter buffer empty interrupt.
  251. ;
  252.     loadport
  253.     setport    MSR
  254.     mov    ah, IER_MS        ; always enable modem status interrupt
  255.     in    al, dx            ; check if clear to send
  256.     test    al, MSR_CTS
  257.     jz    send_pkt_4        ; no - won't enable xmit buffer empty 
  258.                     ; interrupt
  259.  
  260.     or    ah,IER_TxE        ; yes - enable xmit buffer empty 
  261.                     ; interrupt
  262.  
  263. send_pkt_4:
  264.     loadport
  265.     setport    IER
  266.     call    setbit            ; enable
  267.     cli
  268. send_pkt_end:
  269.     clc
  270.     ret
  271.  
  272. ;
  273. ; mod 7/25/89 John Grover
  274. ; - utilizes buffer pointers to ascertain if the
  275. ; - buffer has room for    another character
  276. ;
  277.  
  278. send_char:
  279. ;stuff the character in al into the transmit buffer, but only if there
  280. ;is enough room, otherwise ignore the char.
  281. ;
  282.     assume    ds:nothing
  283.  
  284.     cmp    di, send_buf_head    ;are we out of buffer?
  285.     jne    send_char_ok        ;no - continue
  286.     cmp    pkt_send_sem, 0        ;maybe - if no packets then no
  287.     jne    send_char_1        ;if there are packets then yes
  288.  
  289. send_char_ok:
  290.     stosb                ;store the char.
  291.     cmp    di,send_buf_end        ;do we need to wrap around?
  292.     jne    send_char_1        ;no.
  293.     mov    di,send_buf        ;yes - reload with beginning.
  294. send_char_1:
  295.     ret
  296.  
  297. ;
  298. ; Formulate a dummy ARP reply packet.  ds:si points at the incoming
  299. ; IP packet.
  300. ;
  301.  
  302. arp_reply:
  303.  
  304. ;
  305. ; Save the registers.  Not sure that we need to but it works and I 
  306. ; don't want to change it right now.
  307. ;
  308.     push    ds
  309.     push    es
  310.     push    si
  311.     push    di
  312.     push    cx
  313.  
  314. ;
  315. ; Check to see if the ARP request is to find the hardware address
  316. ; of the local host.  If so, then don't formulate a reply packet.
  317. ;
  318.     mov    cx,4
  319.     mov    ax,si
  320.     mov    di,ax
  321.     mov    ax,ds
  322.     mov    es,ax
  323.     add    di,arp_sprotaddr
  324.     add    si,arp_tprotaddr
  325.     repe    cmpsb            ; Compare source and target
  326.                     ; protocol address
  327.     jnz    arp_reply_2
  328.     pop    cx
  329.     pop    di
  330.     pop    si
  331.     pop    es
  332.     pop    ds
  333.     ret
  334.  
  335. arp_reply_2:
  336. ;
  337. ; Restore registers.
  338. ;
  339.     pop    cx
  340.     pop    di
  341.     pop    si
  342.     push    si
  343.     push    di
  344.     push    cx
  345. ;
  346. ; Restore Ethernet header.
  347. ;
  348.     add    cx,14
  349.     sub    si,14 
  350. ;
  351. ; Ask application layer for a memory buffer in which to store
  352. ; incoming packet.
  353. ;
  354.     push    ds
  355.     push    si            ;save si in case we reject it.
  356.     push    bx
  357.     push    cx
  358.     mov    ax,cs
  359.     mov    es,ax
  360.     mov    ds,ax
  361.     mov    di, offset arp_type
  362.     mov    dl,cs:driver_class
  363.     call    recv_find        ;look up our type.
  364.     pop    cx
  365.     pop    bx
  366.     pop    si
  367.     pop    ds
  368.  
  369.     mov    ax,es            ;is this pointer null?
  370.     or    ax,di
  371.     je    arp_reply_1        ;yes - just free the frame.
  372.  
  373.     push    cx
  374.     push    es
  375.     push    di
  376. ;
  377. ; Save si,di for future use.
  378. ;
  379.     mov    bx,si
  380.     mov    dx,di
  381. ;
  382. ; Set up ARP Reply by first copying the ARP Request packet.
  383. ;
  384.     rep    movsb
  385. ;
  386. ; Skip Ethernet header
  387. ;
  388.     add    bx,14
  389.     add     dx,14
  390. ;
  391. ; Swap target and source protocol addresses from ARP request to ARP 
  392. ; reply packet.
  393. ;
  394.     push    es        ; mods by Joe Doupnik
  395.     mov    si,ds
  396.     mov    es,si
  397.     mov    si,bx        ; incoming packet interior
  398.     sub    si,2+6        ; walk back to originator's Ethernet address
  399.     mov    cx,6        ; six bytes of Ethernet address
  400.     mov    di,dx        ; outgoing packet
  401.     sub    di,2+6+6    ; Ethernet destination address
  402.     rep    movsb        ; copy originator's address as new dest
  403.     pop    es        ;
  404.  
  405.     mov    si,bx
  406.     mov    di,dx    
  407.     mov    cx,4
  408.     add    si,arp_tprotaddr
  409.     add    di,arp_sprotaddr
  410.     rep    movsb
  411.  
  412.     mov    si,bx
  413.     mov    di,dx
  414.     mov    cx,4
  415.     add    si,arp_sprotaddr
  416.     add    di,arp_tprotaddr
  417.     rep    movsb
  418. ;
  419. ; Swap target and source hardware addresses from ARP request to ARP 
  420. ; reply packet.
  421. ;
  422.     mov    si,bx
  423.     mov    di,dx
  424.     mov    cx,6
  425.     add    si,arp_shwaddr
  426.     add    di,arp_thwaddr
  427.     rep    movsb
  428. ;
  429. ; Load source hardware address in ARP reply packet.
  430. ;
  431.     mov    si,bx
  432.     mov    di,dx
  433.     mov    cx,6
  434.     mov    ax,cs
  435.     mov    ds,ax
  436.     mov    si,offset your_addr
  437.     add    di,arp_shwaddr
  438.     rep    movsb
  439. ;
  440. ; Set opcode to REPLY.
  441. ;
  442.     mov    di,dx
  443.     mov    word ptr es:[di].arp_opcode,0200h
  444. ; Give ARP reply packet that has been constructed to the application
  445. ; layer.
  446. ;
  447.     pop    si
  448.     pop    ds
  449.     pop    cx
  450.     assume    ds:nothing
  451.     call    recv_copy
  452.     assume    ds:code
  453.  
  454. arp_reply_1:
  455.  
  456.     pop    cx
  457.     pop    di
  458.     pop    si
  459.     pop    es
  460.     pop    ds
  461.  
  462.     ret
  463.  
  464.     public    get_address
  465. get_address:
  466. ;get the address of the interface.
  467. ;enter with es:di -> place to get the address, cx = size of address buffer.
  468. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  469.     assume    ds:code
  470.     push    di
  471.     push    si
  472.     push    ds
  473. ;
  474. ; Copy psuedo-Ethernet address into buffer allocated by the application
  475. ; layer.
  476. ;
  477.     mov    ax,cs
  478.     mov    ds,ax
  479.     mov    si,offset my_addr
  480.     mov    cx,6
  481.     rep     movsb
  482. ;
  483. ; Set size of psuedo-Ethernet address to be returned.
  484. ;
  485.     mov    cx,6
  486.     pop    ds
  487.     pop    si
  488.     pop    di
  489.     clc
  490.         ret
  491.  
  492.  
  493.  
  494.     public    set_address
  495. set_address:
  496. ;set the address of the interface.
  497. ;enter with es:di -> place to get the address, cx = size of address buffer.
  498. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  499.     assume    ds:nothing
  500.     clc
  501.     ret
  502.  
  503.  
  504. rcv_mode_3:
  505. ;receive mode 3 is thd only one we support, so we don't have to do anything.
  506.     ret
  507.  
  508.  
  509.     public    set_multicast_list
  510. set_multicast_list:
  511. ;enter with ds:si ->list of multicast addresses, cx = number of addresses.
  512. ;return nc if we set all of them, or cy,dh=error if we didn't.
  513.     mov    dh,NO_MULTICAST
  514.     stc
  515.     ret
  516.  
  517.  
  518.     public    get_multicast_list
  519. get_multicast_list:
  520. ;return with nc, es:di ->list of multicast addresses, cx = number of bytes.
  521. ;return    cy, NO_ERROR if we don't remember all of the addresses ourselves.
  522. ;return cy, NO_MULTICAST if we don't implement multicast.
  523.     mov    dh,NO_MULTICAST
  524.     stc
  525.     ret
  526.  
  527.  
  528.     public    terminate
  529. terminate:
  530.     ret
  531.  
  532.     public    reset_interface
  533. reset_interface:
  534. ;reset the interface.
  535.     assume    ds:code
  536.     ret
  537.  
  538.  
  539. ;called    when we    want to determine what to do with a received packet.
  540. ;enter with cx = packet length, es:di -> packet type, dl = packet class.
  541.     extrn    recv_find: near
  542.  
  543. ;called after we have copied the packet into the buffer.
  544. ;enter with ds:si ->the packet, cx = length of the packet.
  545.     extrn    recv_copy: near
  546.  
  547.     extrn    count_in_err: near
  548.     extrn    count_out_err: near
  549.  
  550.     public    recv
  551.  
  552. ;
  553. ; mod 7/25/89 John Grover
  554. ;
  555. ; - added code to check modem status change interrupt. If CTS is
  556. ; - low  turn off transmitter buffer empty interrupt. If CTS is
  557. ; - high turn it on.
  558.  
  559. recv:
  560. ;called from the recv isr.  All registers have been saved, and ds=cs.
  561. ;Upon exit, the interrupt will be acknowledged.
  562.     assume    ds:code
  563. recv_2:
  564.     loadport
  565.     setport    IIR
  566.     in    al,dx            ;any interrupts at all?
  567.     test    al,IIR_IP
  568.     jne    recv_1            ;no.
  569.     and    al,IIR_ID
  570.     cmp    al,IIR_RDA        ;Receiver interrupt
  571.     jne    recv_3
  572.     call    asyrxint
  573.     jmp    recv_2
  574. recv_3:
  575.     cmp    al,IIR_THRE        ;Transmit interrupt
  576.     jne    recv_5
  577.     call    asytxint
  578.     jmp    recv_2
  579. recv_5:
  580. ;process IIR_MSTAT here.
  581. ;  If CTS and packet ready then
  582. ;    enable the    transmit buffer empty interrupt
  583. ;  else
  584. ;    disable the transmit buffer empty interrupt
  585. ;
  586.     cmp    al, IIR_MSTAT
  587.     jne    recv_4
  588.     setport    MSR            ; make sure of CTS status
  589.     mov    ah, IER_TxE        ; get ready to alter xmit buffer empty interrupt
  590.     in    al, dx
  591.     test    al, MSR_CTS        ; is CTS bit set
  592.     jz    recv_5_1        ; no - disable xmit buffer empty int
  593.     cmp    pkt_send_sem, 0        ; yes - is there a packet to xmit
  594.     jbe    recv_2            ; no - all done here
  595.     setport    IER            ; yes - enable xmit buffer empty int
  596.     call    setbit
  597.     jmp    recv_2
  598.  
  599. recv_5_1:
  600.     setport    IER
  601.     call    clrbit
  602.     jmp    recv_2
  603.  
  604. recv_4:
  605. ;process IIR_RLS here
  606. recv_1:
  607.     ret
  608.  
  609.  
  610. ;Process 8250 receiver interrupts
  611. ;
  612. ; mod 7/25/89 John Grover
  613. ; - this branches off when bps < 9600. See asyrxint_a.
  614. ; - Above 9600 bps we go into a loop to process a packet at
  615. ; - a time. If not data ready for a certain amount of time,
  616. ; - the process exits and waits for the next byte. This certain
  617. ; - amount of time to wait depends on the bps and CPU processor speed
  618. ; - and is determined in the initialization of the driver.
  619. ; - Upon receiving the FR_END character for the first frame in the
  620. ; - buffer a semaphore is set which tells recv_frame to run.
  621.  
  622. asyrxint:
  623.  
  624.     push    ds            ; get set up for the routine
  625.     pop    es
  626.     xor    bx, bx
  627.     cmp    baud_rate, 9600         ; below 9600 we're strictly
  628.     jbe    asyrxint_a              ; interrupt driven
  629.     mov    bx, xmit_time
  630. asyrxint_a:
  631.     mov    di,recv_buf_tail
  632.     xor    bp, bp            ; set flag to indicate 1st char
  633.                     ; processed
  634.     mov    si, packet_sem          ; optimization
  635.     loadport
  636.     mov    ah, LSR_DR
  637.  
  638. asyrxint_again:
  639.     xor    cx, cx            ; initialize counter
  640.     setport    LSR
  641. asyrxint_in:
  642.     in    al,dx            ; check for data ready
  643.     test    al,LSR_DR
  644.     jnz    asyrxint_gotit        ; yes - break out of loop
  645.     inc    cx            ; no - increase loop counter
  646.     cmp    cx, bx            ; timeout?
  647.     jae    asyrxint_exit        ; yes - leave
  648.     jmp    asyrxint_in        ; no - keep looping
  649.  
  650. asyrxint_gotit:
  651.     setport    RBR
  652.     in    al,dx
  653.  
  654. ;Process incoming data;
  655. ; If buffer is full, we have no choice but
  656. ; to drop the character
  657.  
  658.     cmp    di,recv_buf_head    ; check for buffer collision
  659.     jne    asyrxint_ok        ; none - continue
  660.     or    si, si                  ; maybe - if there are packets
  661.     jnz    asyrxint_exit        ; yes exit
  662.  
  663. asyrxint_ok:
  664.     stosb
  665.  
  666.     cmp    di,recv_buf_end        ; did we hit the end of the buffer?
  667.     jne    asyrxint_3        ; no.
  668.     mov    di,recv_buf        ; yes - wrap around.
  669.  
  670. asyrxint_3:
  671.     cmp    al,FR_END        ; might    this be    the end of a frame?
  672.     jne    asyrxint_reset        ; no - reset flag and loop
  673.     inc    si                      ; yes - indicate packet ready
  674.     cmp    si, 1                   ; determine if semaphore is <> 1
  675.     jne    asyrxint_chk_flg        ; yes - recv_frame must be active
  676.     inc    recv_pkt_ready          ; no - set flag to start recv_frame
  677.  
  678. asyrxint_chk_flg:
  679.     cmp    bp, 0                   ; was this the first char?
  680.     jne    asyrxint_1              ; no - exit handler
  681. asyrxint_reset:
  682.     inc    bp            ; set 1st character flag
  683.     jmp    asyrxint_again        ; get another character
  684.  
  685. asyrxint_exit:
  686. asyrxint_1:
  687.     mov    recv_buf_tail,di
  688.     mov    packet_sem, si
  689.  
  690.     ret
  691.  
  692.  
  693. ; --------------------------------------------------------------
  694. ;
  695. ;  recv_exiting
  696. ;
  697.     public    recv_exiting
  698. recv_exiting:
  699.     cmp    recv_pkt_ready, 1       ; is a packet ready?
  700.     jne    recv_isr_exit           ; no - skip to end
  701.     push    ax
  702.     push    bx
  703.     push    cx
  704.     push    dx
  705.     push    ds
  706.     push    es
  707.     push    bp
  708.     push    di
  709.     push    si
  710.     push    cs            ; point ds properly
  711.     pop    ds
  712.     mov    recv_pkt_ready,    0    ; reset flag
  713.     sti                ; enable interrupts
  714.  
  715.     call    recv_frame
  716.  
  717.     cli
  718.     pop    si
  719.     pop    di
  720.     pop    bp
  721.     pop    es
  722.     pop    ds
  723.     pop    dx
  724.     pop    cx
  725.     pop    bx
  726.     pop    ax
  727. recv_isr_exit:
  728.     ret
  729.  
  730.  
  731. ; --------------------------------------------------------------
  732. ;
  733. ;  recv_frame
  734. ;
  735. ; mod 7/25/89 John Grover
  736. ;
  737. ; - recv_frame now operates with interrupts on. It is triggered
  738. ; - by the recv_pkt_ready flag and continues until all bytes
  739. ; - in all packets in the buffer have been transmitted to the upper
  740. ; - layer.
  741. ;
  742.  
  743.   ifdef debug
  744.     public recv_frame
  745.   endif
  746. recv_frame:
  747.     cmp    packet_sem, 0        ; should we do this?
  748.     jz    recv_frame_end        ; no - exit
  749.     mov    si,recv_buf_head    ;process characters.
  750.     xor    cx,cx            ;count up the size here.
  751. recv_frame_1:
  752.  
  753.     call    recv_char        ;get a char.
  754.     je    recv_frame_2        ;go if no more chars.
  755.     cmp    al,FR_ESC        ;an escape?
  756.     je    recv_frame_1        ;yes - don't count this char.
  757.     inc    cx            ;no - count this one.
  758.     jmp    recv_frame_1
  759. recv_frame_2:
  760.  
  761.     jcxz    recv_frame_3        ;count zero? yes - just free the frame.
  762. ;
  763. ; Add Ethernet header.  As well, ensure that minimum packet size is 60
  764. ; bytes; some application packages actually check for minimum packet size.
  765. ;
  766.     add    cx,14 
  767.     cmp    cx, 60
  768.     jge     recv_next
  769.     mov    cx, 60    
  770. ;
  771. recv_next:
  772.     push    cx
  773.     push    si            ;save si in case we reject it.
  774.     push    bx
  775.  
  776.     push    cs
  777.     pop    es
  778.     mov    di, offset ip_type
  779.     mov    dl,cs:driver_class
  780.     call    recv_find        ;look up our type.
  781.  
  782.     pop    bx
  783.     pop    si
  784.     pop    cx
  785.  
  786.     mov    ax,es            ;is this pointer null?
  787.     or    ax,di
  788.     je    recv_frame_3        ;yes - just free the frame.
  789.  
  790.     push    cx
  791.     push    es            ;remember where the buffer pointer is.
  792.     push    di
  793. ;
  794. ; Fix up the Ethernet header added to the incoming packet.
  795. ;
  796.     call    fix_header
  797. fix_ret:
  798.  
  799.     mov    si,recv_buf_head    ;process characters.
  800. recv_frame_4:
  801.     call    recv_char
  802.     je    recv_frame_6        ;yes - we're all done.
  803.     cmp    al,FR_ESC        ;an escape?
  804.     jne    recv_frame_5        ;no - just store it.
  805.  
  806.     call    recv_char        ;get the next character.
  807.     je    recv_frame_6
  808.     cmp    al,T_FR_ESC
  809.     mov    al,FR_ESC        ;assume T_FR_ESC
  810.     je    recv_frame_5        ;yup, that's it    - store FR_ESC
  811.     mov    al,FR_END        ;nope, store FR_END
  812. recv_frame_5:
  813.     stosb                ;store the byte.
  814.     jmp    recv_frame_4
  815. recv_frame_6:
  816.     mov    recv_buf_head,si    ;we're skipped to the end.
  817.  
  818.     pop    si            ;now give the frame to the client.
  819.     pop    ds
  820.     pop    cx
  821.     assume    ds:nothing
  822.  
  823.     call    recv_copy
  824.     push    cs
  825.     pop    ds
  826.     assume    ds:code
  827.     jmp    recv_frame_end
  828.  
  829. recv_frame_3:
  830.     mov    recv_buf_head,si    ;remember the new starting point.
  831. recv_frame_end:
  832.     dec    packet_sem
  833.     cmp    packet_sem, 0        ; are there more packets ready?
  834.     ja    recv_frame              ; yes - execute again
  835.     ret
  836.  
  837. ; --------------------------------------------------------------
  838. ;
  839. ;  recv_char
  840. ;
  841. ; mod 7/25/89 John Grover
  842. ; - Now    uses buffer pointers to determine if there are
  843. ; - characters left.
  844. ;
  845.  
  846. recv_char:
  847. ;enter with si -> receive buffer, bx = receive count.  Wrap around if needed.
  848. ;return with nz, al = next char.  Return zr if there are no more chars in
  849. ;  this frame.
  850. ;
  851.     lodsb
  852.     cmp    si,recv_buf_end
  853.     jb    recv_char_1
  854.     mov    si,recv_buf
  855. recv_char_1:
  856.     mov    bx, recv_buf_tail
  857.     cmp    si, bx
  858.     je    recv_char_2
  859.     cmp    al,FR_END
  860. recv_char_2:
  861.     ret
  862.  
  863. ;
  864. ; Set destination and source addressess and packet type in an
  865. ; Ethernet header.
  866. ;
  867. fix_header:
  868. ;
  869. ; Set destination address.
  870. ;
  871.     mov    ax,0000h
  872.     stosw
  873.     mov    ax,0c3c4h
  874.     stosw
  875.     mov    ax,0c2cch
  876.     stosw
  877. ;
  878. ; Set source address.
  879. ;
  880.     mov    ax,0201h
  881.     stosw
  882.     mov    ax,0403h
  883.     stosw
  884.     mov    ax,0605h
  885.     stosw
  886. ;
  887. ; Set packet type to IP.
  888. ;
  889.     mov    ax, 0008h
  890.     stosw    
  891.     ret
  892.  
  893. ;Handle 8250 transmitter interrupts
  894.  
  895. ; --------------------------------------------------------------
  896. ;
  897. ;  asytxint
  898. ;
  899. ; mod 7/25/89
  900. ; - Transmits one character and then exits. Upon last character
  901. ; - to transmit modem status and transmitter buffer empty interrupt
  902. ; - are disabled.
  903. ;
  904.  
  905. asytxint:
  906.  
  907. asytxint_2:
  908.  
  909. ;
  910. ; mod  3/16/90  Denis DeLaRoca
  911. ; - for 16550 fifo uart stuff up to 16 chars at a time
  912. ; - for  8250 uart can only output one char at a time
  913. ;
  914.     cmp    is_16550,1              ;have 16550 uart
  915.     jne    asytxint_8250           ;no, handle as 8250
  916.  
  917. asytxint_16550:
  918.     loadport
  919.     setport    THR
  920.     mov    cx,16                   ;fifo fill-loop counter
  921.     mov     si,send_buf_head        ;current head of buffer
  922. asytxint_next:
  923.     lodsb                ;fetch next char
  924.     cmp    si,send_buf_end        ;past end of buffer
  925.     jne     asytxint_fill
  926.     mov    si,send_buf        ;yes, wrap around 
  927. asytxint_fill:
  928.     out    dx,al            ;output char
  929.     cmp    si,send_buf_tail    ;any more chars to output
  930.     je      asytxint_no_more        ;none...
  931.     loop    asytxint_next        ;loop while fifo not full
  932.     mov    send_buf_head,si       ;save last char position used
  933.     jmp    asytxint_1        ;and exit
  934. asytxint_no_more:
  935.     mov     send_buf_head,si        ;save last char position used
  936.     jmp    asytxint_disable    ;go disable status interrupts
  937.  
  938. asytxint_8250:
  939.     mov    si,send_buf_head    ; yes - load one
  940.     lodsb                ;
  941.     cmp    si,send_buf_end        ;have we hit the end yet?
  942.     jne    asytxint_3        ;no.
  943.     mov    si,send_buf        ;yes - wrap around
  944. asytxint_3:
  945.     loadport
  946.     setport    THR
  947.     out    dx,al
  948.     mov    send_buf_head,si    ; store our location
  949.     cmp    si, send_buf_tail    ; more to xmit?
  950.     jne    asytxint_1        ; yes just exit
  951.  
  952. ;No more characters to transmit -- disable transmit interrupts.
  953.  
  954. asytxint_disable:
  955.     setport    IER            ;Disable transmit and modem
  956.     mov    ah,IER_TxE or IER_MS    ; status interrupts
  957.     call    clrbit
  958.     mov    pkt_send_sem, 0        ; indicate we're finished
  959. asytxint_1:
  960.     ret
  961.  
  962.  
  963. ;Set bit(s) in I/O port
  964. setbit:
  965. ;enter with dx = port, ah = bit to set.
  966.     in    al,dx
  967.     or    al,ah
  968.     out    dx,al
  969.     ret
  970.  
  971.  
  972. ;Clear bit(s) in I/O port
  973. clrbit:
  974. ;enter with dx = port, ah = bit to set.
  975.     in    al,dx
  976.     not    al            ;perform an and-not using DeMorgan's.
  977.     or    al,ah
  978.     not    al
  979.     out    dx,al
  980.     ret
  981.  
  982.  
  983. ;any code after this will not be kept after initialization.
  984. end_resident    label    byte
  985.  
  986.     public    usage_msg
  987. usage_msg    db    "usage: ETHERSLIP [-n] [-d] [-w] packet_int_no [-h] [int_no]",CR,LF
  988.         db    "   [io_addr] [baud_rate]",CR,LF
  989.         db    "   [send_buf_size] [recv_buf_size]",CR,LF
  990.         db    "   -h enables hardware handshaking",CR,LF,'$'
  991.  
  992.     public    copyright_msg
  993. copyright_msg    db    "Packet driver for ETHERSLIP, version ",'0'+(majver / 10),'0'+(majver mod 10),"."
  994.         db    '0'+version,CR,LF
  995.         db    "Portions Copyright 1988 Phil Karn",CR,LF,'$'
  996.         db    "Portions Copyright 1991 Michael Martineau",CR,LF
  997.         db    " 5 Nov 1991",cr,lf,'$'
  998.  
  999. approximate_msg    db    "Warning: This baud rate can only be approximated using the 8250",CR,LF
  1000.         db    "because it is not an even divisor of 115200",CR,LF,'$'
  1001.  
  1002. is_16550_msg    db      "16550 Uart detected, FIFO will be used",CR,LF,'$'
  1003.  
  1004. class_name_ptr    dw    ?
  1005. class_name    db    "Interface class ",'$'
  1006. int_no_name    db    "Interrupt number ",'$'
  1007. io_addr_name    db    "I/O port ",'$'
  1008. baud_rate_name    db    "Baud rate ",'$'
  1009. send_buf_name    db    "Send buffer size ",'$'
  1010. recv_buf_name    db    "Receive buffer size ",'$'
  1011. unusual_com1    db    "That's unusual!  Com1 (0x3f8) usually uses interrupt 4!",CR,LF,'$'
  1012. unusual_com2    db    "That's unusual!  Com2 (0x2f8) usually uses interrupt 3!",CR,LF,'$'
  1013.  
  1014.     extrn    set_recv_isr: near
  1015.  
  1016. ;enter with si -> argument string, di -> word to store.
  1017. ;if there is no number, don't change the number.
  1018.     extrn    get_number: near
  1019.  
  1020. ;enter with dx -> name of word, di -> dword to print.
  1021.     extrn    print_number: near
  1022.  
  1023. ;enter with si -> argument string.
  1024. ;skip spaces and tabs.  Exit with si -> first non-blank char.
  1025.     extrn    skip_blanks: near
  1026.  
  1027.  
  1028.     public    parse_args
  1029. parse_args:
  1030. ;exit with nc if all went well, cy otherwise.
  1031.     call    skip_blanks
  1032.     cmp    al,'-'            ;did they specify a switch?
  1033.     jne    not_switch
  1034.     cmp    byte ptr [si+1],'h'    ;did they specify '-h'?
  1035.     je    got_hardware_switch
  1036.     stc                ;no, must be an error.
  1037.     ret
  1038. got_hardware_switch:
  1039.     mov    hardware_switch,1
  1040.     add    si,2            ;skip past the switch's characters.
  1041.     jmp    parse_args        ;go parse more arguments.
  1042. not_switch:
  1043.     mov    di,offset int_no
  1044.     call    get_number
  1045.     mov    di,offset io_addr
  1046.     call    get_number
  1047.     mov    di,offset baud_rate
  1048.     call    get_number
  1049.     mov    di,offset send_buf_size
  1050.     call    get_number
  1051.     mov    di,offset recv_buf_size
  1052.     call    get_number
  1053.     clc
  1054.     ret
  1055.  
  1056.  
  1057. ; --------------------------------------------------------------
  1058. ;
  1059. ;  etopen
  1060. ;
  1061. ; mod 7/25/89 John Grover
  1062. ; - Contains a loop to determine a pseudo timeout for asyrxint.
  1063. ; - The value is determined by transmitting characters in a
  1064. ; - loop whose clock cycles are nearly the same as the "sister"
  1065. ; - loop in asyrxint. The per character, maximum time used
  1066. ; - basis which is then multiplied by a factor to achieve a timeout
  1067. ; - value for the particular bps and CPU speed of the host.
  1068.  
  1069.     public    etopen
  1070. etopen:
  1071.     pushf
  1072.     cli
  1073. ;
  1074. ; mod  3/16/90  Denis DeLaRoca
  1075. ; - determine if 16550 uart is present
  1076. ; - if so initialize fifo buffering
  1077. ;
  1078.     loadport
  1079.     setport    FCR
  1080.     mov    al,FIFO_ENABLE
  1081.     out    dx,al                   ;outportb(base+FCR,(char) FIFO_ENABLE)
  1082.     setport    IIR
  1083.     in    al,dx                   ;inportb(base+IIR)
  1084.     and    al,IIR_FIFO_ENABLED     ;     & IIR_FIFO_ENABLED
  1085.     cmp    al,IIR_FIFO_ENABLED    ;both bits must be on   NEW, 11/20/90
  1086.     jnz    not_16550               ;nope, we don't have 16550 chip
  1087.     mov    is_16550,1              ;yes, note fact
  1088.     mov    al,FIFO_SETUP           ;and setup FIFO
  1089.     setport    FCR
  1090.     out    dx,al                   ;outportb(base+FCR,(char) FIFO_SETUP)
  1091.  
  1092.     mov    dx,offset is_16550_msg
  1093.     mov    ah,9
  1094.     int    21h            ;let user know about 16550
  1095.  
  1096. not_16550:
  1097.     loadport            ;Purge the receive data buffer
  1098.     setport    RBR
  1099.     in    al,dx
  1100.  
  1101.     ;Set line control register: 8 bits, no parity
  1102.     mov    al,LCR_8BITS
  1103.     setport    LCR
  1104.     out    dx,al
  1105.  
  1106.     ;Turn on receive interrupt enable in 8250, leave transmit
  1107.     ; and modem status interrupts turned off for now
  1108.     mov    al,IER_DAV
  1109.     setport    IER
  1110.     out    dx,al
  1111.  
  1112.     ;Set modem control register: assert DTR, RTS, turn on 8250
  1113.     ; master interrupt enable (connected to OUT2)
  1114.  
  1115.     mov    al,MCR_DTR or MCR_RTS or MCR_OUT2
  1116.     setport    MCR
  1117.     out    dx,al
  1118.  
  1119. ;compute the divisor given the baud rate.
  1120.     mov    dx,baudclk+2
  1121.     mov    ax,baudclk
  1122.     mov    bx,0
  1123. asy_speed_1:
  1124.     inc    bx
  1125.     sub    ax,baud_rate
  1126.     sbb    dx,baud_rate+2
  1127.     jnc    asy_speed_1
  1128.     dec    bx
  1129.     add    ax,baud_rate
  1130.     adc    dx,baud_rate+2
  1131.     or    ax,dx
  1132.     je    asy_speed_2
  1133.  
  1134.     mov    dx,offset approximate_msg
  1135.     mov    ah,9
  1136.     int    21h
  1137.  
  1138. asy_speed_2:
  1139.  
  1140.     loadport            ;Purge the receive data buffer
  1141.     setport    RBR
  1142.     in    al,dx
  1143.  
  1144.     mov    ah,LCR_DLAB        ;Turn on divisor latch access bit
  1145.     setport    LCR
  1146.     call    setbit
  1147.  
  1148.     mov    al,bl            ;Load the two bytes of the divisor.
  1149.     setport    DLL
  1150.     out    dx,al
  1151.     mov    al,bh
  1152.     setport    DLM
  1153.     out    dx,al
  1154.  
  1155.     mov    ah,LCR_DLAB        ;Turn off divisor latch access bit
  1156.     setport    LCR
  1157.     call    clrbit
  1158.  
  1159.     call    set_recv_isr        ;Set interrupt vector to SIO handler
  1160.  
  1161. ;set up the various pointers.
  1162.     mov    dx,offset end_resident
  1163.     mov    send_buf,dx
  1164.     mov    send_buf_head,dx
  1165.     mov    send_buf_tail,dx
  1166.     add    dx,send_buf_size
  1167.     mov    send_buf_end,dx
  1168.  
  1169.     mov    recv_buf,dx
  1170.     mov    recv_buf_head,dx
  1171.     mov    recv_buf_tail,dx
  1172.     add    dx,recv_buf_size
  1173.     mov    recv_buf_end,dx
  1174.     push    dx            ;save the ending address.
  1175.  
  1176.     ; the following code attempts to determine a pseudo timeout
  1177.     ; value    to use in the loop that waits for an incoming character
  1178.     ; in asyrxint. The value returned in xmit_time is the number of
  1179.     ; loops processed between characters - therefore the loop used below
  1180.     ; is and should    remain similar to the loop used in asyrxint.
  1181.  
  1182.     xor    ax, ax            ; we'll send a 0
  1183.     mov    ah, LSR_THRE
  1184.     mov    cx, 10h            ; take the highest of 16 runs
  1185.     xor    si, si            ; will hold highest value
  1186.  
  1187. xmit_time_start:
  1188.  
  1189.     xor    di, di            ; initialize counter
  1190.     loadport
  1191.     setport    THR            ; xmit a character
  1192.     out    dx, al
  1193.     setport    LSR               ; set up    to check for an empty buffer
  1194.  
  1195.     ; next is the loop actually being timed
  1196.  
  1197. xmit_time_top:
  1198.     in    al, dx
  1199.     test    al, ah
  1200.     jnz    xmit_time_done
  1201.     inc    di
  1202.     cmp    cx, cx            ; these next few instructions do nothing
  1203.     jmp    xmit_time_1        ;  except maintain similarity with the
  1204.                     ;  "sister" loop in asyrxint
  1205. xmit_time_1:
  1206.     jmp    xmit_time_top
  1207.  
  1208. xmit_time_done:                ; end of timed loop
  1209.  
  1210.  
  1211.  
  1212.     cmp    si, di            ; compare highest value with new value
  1213.     ja    xmit_time_end        ; no bigger - just loop
  1214.     mov    si, di            ; bigger - save it
  1215.  
  1216. xmit_time_end:
  1217.     loop    xmit_time_start        ; bottom of outer loop
  1218.  
  1219.     shl    si, 1            ; we'll wait 8 characters worth
  1220.     shl    si, 1
  1221.     shl    si, 1
  1222.     mov    xmit_time, si        ; retain largest value
  1223.  
  1224.     ; end of pseudo timer determination
  1225.  
  1226.     mov    al, int_no        ; Get board's interrupt vector
  1227.     add    al, 8
  1228.     cmp    al, 8+8            ; Is it a slave 8259 interrupt?
  1229.     jb    set_int_num        ; No.
  1230.     add    al, 70h - 8 - 8        ; Map it to the real interrupt.
  1231. set_int_num:
  1232.     xor    ah, ah            ; Clear high byte
  1233.     mov    int_num, ax        ; Set parameter_list int num.
  1234.  
  1235.     pop    dx            ;return the ending address.
  1236.     popf
  1237.     clc                ;indicate no errors.
  1238.     ret
  1239.  
  1240.     public    print_parameters
  1241. print_parameters:
  1242. ;echo our command-line parameters
  1243.     cmp    class_name_ptr,0
  1244.     je    echo_args_1
  1245.  
  1246.     mov    dx,offset class_name
  1247.     mov    ah,9
  1248.     int    21h
  1249.     mov    dx,class_name_ptr
  1250.     mov    ah,9
  1251.     int    21h
  1252.     jmp    short echo_args_2
  1253. echo_args_1:
  1254.     mov    di,offset driver_class
  1255.     mov    dx,offset class_name
  1256.     call    print_number
  1257. echo_args_2:
  1258.  
  1259.     mov    di,offset int_no
  1260.     mov    dx,offset int_no_name
  1261.     call    print_number
  1262.     mov    di,offset io_addr
  1263.     mov    dx,offset io_addr_name
  1264.     call    print_number
  1265.  
  1266.     cmp    io_addr,03f8h        ;is this com1?
  1267.     jne    ia_com2
  1268.     mov    dx,offset unusual_com1
  1269.     cmp    int_no,4        ;com1 usually uses int 1.
  1270.     jne    ia_unusual
  1271.     jmp    short ia_usual
  1272. ia_com2:
  1273.     cmp    io_addr,02f8h        ;is this com2?
  1274.     jne    ia_usual        ;no.
  1275.     mov    dx,offset unusual_com2
  1276.     cmp    int_no,3        ;com2 usually uses int 3.
  1277.     je    ia_usual
  1278. ia_unusual:
  1279.     mov    ah,9
  1280.     int    21h
  1281. ia_usual:
  1282.     mov    di,offset baud_rate
  1283.     mov    dx,offset baud_rate_name
  1284.     call    print_number
  1285.     mov    di,offset send_buf_size
  1286.     mov    dx,offset send_buf_name
  1287.     call    print_number
  1288.     mov    di,offset recv_buf_size
  1289.     mov    dx,offset recv_buf_name
  1290.     call    print_number
  1291.     ret
  1292. code    ends
  1293.     end
  1294.